﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Net;
// using System.Web.Http.Filters;
using System.Threading;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authentication;
using Daemon.ViewModel;
using Daemon.Common.Middleware;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Memory;
using Daemon.Common.Cache;
using Daemon.Common.Const;
using Daemon.Model;
using Daemon.Common;
using DaemonAPI.Helpers;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using Daemon.Repository.Contract;
using Daemon.Data.Infrastructure.Auth;
using Daemon.Common.Auth;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace DaemonAPI.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class DaemonAuthFilter : ActionFilterAttribute
    {
        private const int DEFAULT_SESSION_TIMEOUT = 60 * 24;

        private readonly IConfiguration _configuration;

        private readonly IDaemonDistributedCache _cache;

        private readonly ApiDBContent _context;

        private readonly ITokenInfoRepository _tokenInfoRepository;

        private readonly IClientConfigRepository _clientConfigRepository;

        private readonly IAdminUserRepository _adminUserRepository;

        private readonly ClientAuthCache _clientAuthCache;

        private readonly IDaemonDistributedCache _daemonDistributedCache;

        public DaemonAuthFilter(IConfiguration configuration, IDaemonDistributedCache cache,
            ITokenInfoRepository tokenInfoRepository,
            IClientConfigRepository clientConfigRepository,
            IAdminUserRepository adminUserRepository,
            ClientAuthCache clientAuthCache,
            IDaemonDistributedCache daemonDistributedCache,
            ApiDBContent context)
        {
            this._configuration = configuration;
            _cache = cache;
            _context = context;
            _tokenInfoRepository = tokenInfoRepository;
            _clientConfigRepository = clientConfigRepository;
            _clientAuthCache = clientAuthCache;
            _adminUserRepository = adminUserRepository;
            _daemonDistributedCache = daemonDistributedCache;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (SkipAuthorization(context))
            {
                await next();
                return;
            }

            var token = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
            if (string.IsNullOrEmpty(token))
            {
                context.Result = new ResultModel(HttpStatusCode.Unauthorized, "");
                return;
            }

            token = token.Replace("Bearer ", "");
            var claims = TokenHelper.ValidateToken(token);
            if (claims != null)
            {
                var userId = claims.FirstOrDefault(r => r.Type == "Id")?.Value;
                var prefix = claims.FirstOrDefault(r => r.Type == "Prefix")?.Value;
                var userName = claims.FirstOrDefault(r => r.Type == "Name")?.Value;
                if (string.IsNullOrEmpty(userId))
                {
                    context.Result = new ResultModel(HttpStatusCode.Unauthorized, "");
                }

                IAuthInfo authInfo = _clientAuthCache.GetAuthInfoByClientUser(prefix + "_" + userName);
                BaseAuthUser userEntity = null;
                if (authInfo != null)
                {
                    userEntity = authInfo.UserEntity;
                }

                if (userEntity == null)
                {
                    try
                    {
                        var user = _adminUserRepository.FindAll().Where(r => r.Id == Convert.ToInt32(userId)).Select(r => new BaseAuthUser() { Id = r.Id, UserType = "WX", UserName = r.UserName }).ToList()[0];
                        authInfo = new AuthInfoEF(user);
                        userEntity = authInfo?.UserEntity;
                        _clientAuthCache.AddClientUserEntryAsync(prefix + "_" + userName, authInfo);
                    }
                    catch (Exception ex)
                    {
                        context.Result = new ObjectResult(new ResultModel(HttpStatusCode.Unauthorized, "请重新登录！"));
                        return;
                    }
                }

                if (userEntity == null)
                {
                    context.Result = new ObjectResult(new ResultModel(HttpStatusCode.Unauthorized, "请重新登录！"));
                    return;
                }
            }
            else
            {
                context.Result = new ObjectResult(new ResultModel(HttpStatusCode.Unauthorized, "请重新登录！"));
                return;
            }

            await next();
        }

        private bool SkipAuthorization(ActionExecutingContext actionContext)
        {
            Contract.Assert(actionContext != null);
            var requestPath = actionContext.HttpContext.Request.Path;
            var header = actionContext.HttpContext.Request.Headers["Auth-key"];
            if (header.Any() && !string.IsNullOrEmpty(header.FirstOrDefault()))
            {
                var authKey = PasswordHelper.Rfc2898Decrypt(header.FirstOrDefault(), "daemon");
                if (authKey == GetAuthKey())
                {
                    return true;
                }
            }

            var attributeList = (actionContext.ActionDescriptor as ControllerActionDescriptor).MethodInfo.GetCustomAttributes(true);
            var controllerAttribute = actionContext.Controller.GetType().CustomAttributes;
            var controllerAuthorityAttribute = (Daemon.Common.Attribute.AllowAnonymousAttribute)attributeList.Where(a => a.GetType().Name == typeof(Daemon.Common.Attribute.AllowAnonymousAttribute).Name).ToList().FirstOrDefault();
            if (controllerAuthorityAttribute != null)
            {
                return true;
            }

            return false;
        }

        private string GetAuthKey()
        {
            var authKey = _cache.Get<string>(CacheKeyConst.AUTH_KEY);
            if (!string.IsNullOrEmpty(authKey))
            {
                return authKey;
            }

            authKey = _context.ClientConfig.FirstOrDefault()?.AuthKey;
            return authKey;
        }


        public class BE_PostPermissionList
        {
            public string permid { get; set; }

            public int ModuleId { get; set; }
        }



    }

}
